﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Yammer.api;

namespace ScrumPilot.Domain.BPL
{
    public class YammerServices : BusinessProcessLayer
    {
        private YammerConfigParameters _config;
        private YammerClient _myYammer;
        protected YammerClient MyYammerClient
        {
            get
            {
                if (this._myYammer == null)
                {
                    this.InitParameters();
                    this._myYammer = new YammerClient(this._config.ConsumerKey, this._config.ConsumerSecret,
                                                        this._config.BackUrl, this._config.Code, this._config.Token);
                }
                return this._myYammer;
            }
        }

        public Boolean IsImpersonated = false;

        public Boolean IsProballyReadyToPost
        {
            get { return this._config.IsProballyReadyToPost; }
        }

        public Boolean HaveRequiredParameters
        {
            get { return this._config.HaveRequiredParameters; }
        }

        /// <summary>
        /// Construtor use from an user (and try to impersonate him)
        /// </summary>
        /// <param name="iUserId"></param>
        public YammerServices(int iUserId)
        {
            this.InitParameters();

            using (var unitOfWork = new UnitOfWork())
            {
                var usr = unitOfWork.UserRepositery.GetFullById(iUserId);
                if (usr != null)
                {
                    // User exist and have Yammer Token
                    if (usr.YammerUserParameters != null &&
                        (!String.IsNullOrEmpty(usr.YammerUserParameters.Code) ||
                         !String.IsNullOrEmpty(usr.YammerUserParameters.Token)))
                    {
                        this._config.Code = usr.YammerUserParameters.Code;
                        this._config.Token = usr.YammerUserParameters.Token;
                        this.IsImpersonated = true;
                    }
                    else
                    {
                        // Usualy, we can connect to Yammer with embedded Yammer Admin user

                        // two case : 
                        // not yet in Yammer
                        var yammerUsr = this.MyYammerClient.GetUserByMail(usr.mail);
                        if (yammerUsr == null)
                        {
                            if (!String.IsNullOrEmpty(usr.mail) && usr.isyammerinvited)
                            {
                                // send invitation to Yammer
                                this.MyYammerClient.SendInvitation(usr.mail);
                                EventLog.WriteEntry("ScrumPilot WS", "Send Yammer Invitation to " + usr.mail, EventLogEntryType.Information);
                                usr.isyammerinvited = true;
                                unitOfWork.Save();
                            }
                        }
                        else
                        {
                            // user is in yammer : we found him
                            // check if he is in token Impersonation list
                            var impersonateToken = this.MyYammerClient.GetTokenFromUser(usr.mail, true);
                            if (impersonateToken != null)
                            {
                                // set our token from this user
                                this._config.Token = impersonateToken;
                                this._config.Code = null;
                                this.IsImpersonated = true;
                            }
                        }
                    }

                    // if we don't find a correct user to post the message
                }
            }
        }


        /// <summary>
        /// Contructor use from Yammer Admin ScrumPilot actor
        /// </summary>
        public YammerServices()
        {
            this.InitParameters();
        }

        public String GetLoginAndAuthorizedUrl(String backUrl = null)
        {
            this._config.BackUrl = backUrl;
            return this.MyYammerClient.GetLoginLinkUri();
        }

        public void PostMessage(String message, String projectName, String iteration,
                                String openGraphUrl, String openGraphTitle)
        {
            if (this._config.Token != null)
            {
                //this.MyYammerClient.AccessToken = impersonateToken;
                var topics = new List<String> { this._config.DefaultTopic, projectName, iteration };
                var result = this.MyYammerClient.PostMessage(message, this._config.PublishGroup,
                                                topics, new OpenGraphInMessage
                                                            {
                                                                og_url = openGraphUrl,
                                                                og_title = openGraphTitle,
                                                                og_fetch = true
                                                            });

                var messageResult = result.meta.current_user_id + " | Messages:";
                messageResult = result.messages.Aggregate(messageResult, (current, m) => current + ("[" + m.id + "/" + m.body.plain + "]"));

                EventLog.WriteEntry("ScrumPilot WS", messageResult, EventLogEntryType.Information);

            }
            else
            {
                EventLog.WriteEntry("ScrumPilot WS", "Yammer : no token", EventLogEntryType.Warning);
            }
        }

        /// <summary>
        /// Save the token when a user have authorized
        /// Scrum Pilot to interact with Yammer in his name
        /// </summary>
        /// <param name="userId">User who authorize</param>
        /// <param name="code">Authorization code from Yammer</param>
        public void SaveToken(int userId, String code)
        {
            // set the authorization code & Ask the token from this user/code
            this.MyYammerClient.SetAuthorizationCode(code);
            using (var unitOfWork = new UnitOfWork())
            {
                var usr = unitOfWork.UserRepositery.GetFullById(userId);
                usr.YammerUserParameters = new YammerUserParameters
                {
                    YammerId = this.MyYammerClient.GetUserInfo().id,
                    Code = code,
                    Token = this.MyYammerClient.GetToken()
                };
                unitOfWork.Save();
            }
        }

        /// <summary>
        /// Save the token of ScrumPilot Actor 
        /// </summary>
        /// <param name="code">Authorization code from Yammer</param>
        public void SaveYammerAdminToken(String code)
        {
            if (code == null) code = this._config.Code;
            // set the authorization code &Ask the token from this user/code
            this.MyYammerClient.SetAuthorizationCode(code);
            using (var unitOfWork = new UnitOfWork())
            {
                var spp = unitOfWork.ScrumPilotParamRepository.GetOne();
                spp.yammerauthorizedcode = code;
                spp.yammercurrenttoken = this.MyYammerClient.GetToken();
                unitOfWork.Save();
            }
        }

        private void InitParameters()
        {
            if (this._config == null || String.IsNullOrEmpty(this._config.ConsumerKey))
            {
                using (var unitOfWork = new UnitOfWork())
                {
                    var spp = unitOfWork.ScrumPilotParamRepository.GetOne();
                    this._config = new YammerConfigParameters
                                       {
                                           ConsumerKey = spp.yammerconsumer_key,
                                           ConsumerSecret = spp.yammerconsumer_secret,
                                           Code = spp.yammerauthorizedcode,
                                           Token = spp.yammercurrenttoken,
                                           DefaultTopic = spp.yammertopic,
                                           PublishGroup = spp.yammergroup ?? -1
                                       };
                }
            }

            // Work in progress : Param in XML file
            //var xy = new YammerConfigParameters()
            //             {
            //                 ConsumerKey = this._yammerClient,
            //                 ConsumerSecret = this._yammerSecret,
            //                 Code = this._yammerCode,
            //                 Token = this._yammerToken,
            //                 DefaultTopic = this._yammerScrumpilotTopic
            //             };
            //var xs = new XmlSerializer(typeof(YammerConfigParameters));
            //using (var wr = new MemoryStream())
            //{
            //    xs.Serialize(wr, xy);
            //    var a = wr.ToArray();

            //    var v = System.Text.Encoding.Default.GetString(a);
            //}

        }
    }

    public class YammerConfigParameters
    {
        public String ConsumerKey { get; set; }
        public String ConsumerSecret { get; set; }
        public String Code { get; set; }
        public String Token { get; set; }
        public long PublishGroup { get; set; }
        public String DefaultTopic { get; set; }
        public String BackUrl { get; set; }

        public Boolean HaveRequiredParameters
        {
            get
            {
                return !String.IsNullOrEmpty(this.ConsumerKey) &&
                       !String.IsNullOrEmpty(this.ConsumerSecret) &&
                       this.PublishGroup > 0;
            }
        }

        public Boolean IsProballyReadyToPost
        {
            get
            {
                return (HaveRequiredParameters ||
                       !String.IsNullOrEmpty(this.Token));
            }
        }
    }

    /// <summary>
    /// Wrapper of User Parameters around Yammer subject
    /// </summary>
    public class YammerUserParameters
    {
        public long YammerId { get; set; }
        public String Code { get; set; }
        public String Token { get; set; }

        public override string ToString()
        {
            using (var ms = new MemoryStream())
            {
                var serializer = new JsonSerializer();
                // serialize product to BSON
                var writer = new BsonWriter(ms);
                serializer.Serialize(writer, this);
                return Convert.ToBase64String(ms.ToArray());
            }
        }

        public static implicit operator YammerUserParameters(String bson)
        {
            if (bson != null)
            {
                try
                {
                    using (var ms = new MemoryStream(Convert.FromBase64String(bson)))
                    {
                        var serializer = new JsonSerializer();
                        var reader = new BsonReader(ms);

                        var deserializedParams = serializer.Deserialize<YammerUserParameters>(reader);
                        return deserializedParams;
                    }
                }
                catch (Exception)
                {
                    return null;
                }
            }
            return null;
        }
    }
}
